#include "chitu_math.h"
#include <stdio.h>

#define CHITU_MUT 25214903917ULL
#define CHITU_ADD 11ULL
#define CHITU_MOD 281474976710656ULL
#define CHITU_RAND_MAX CHITU_MOD

uint64_t chitu_seed = 33;
double chitu_odt = 1 / 3;

inline void chitu_srand(uint64_t x)
{
    chitu_seed = x;
}

inline uint64_t chitu_rand()
{
    chitu_seed = (chitu_seed * CHITU_MUT + CHITU_ADD) % CHITU_MOD;
    return chitu_seed;
}

inline double chitu_random() 
{
    
    return (double)chitu_rand() / (double)CHITU_RAND_MAX;
}

inline uint64_t chitu_randint(int64_t start, int64_t end) 
{
    return ((end - start) * chitu_random() + start);
}

inline double chitu_randfloat(double start, double end) 
{
    return ((end - start) * chitu_random() + start);
}

//通用数学部分

inline double chitu_squre(double x) 
{
    return x*x;
}

inline double chitu_sqrt(double x) 
{
    return sqrt(x);
}

inline double chitu_cube(double x) 
{
    return x*x*x;
}

inline double chitu_cbrt(double x) 
{
    return exp(log(x) * chitu_odt);
}

inline double chitu_pow(double x, double n) 
{
    return pow(x, n);
}

double chitu_array_sum(chitu_array *a)
{
    double output = 0;
    for (uint64_t i = 0; i < a->length; i++)
        output += a->val[i];
    return output;
}

inline double chitu_array_even(chitu_array *a)
{
    return chitu_array_sum(a) / a->length;
}

double chitu_array_variance(chitu_array *a)
{
    double a_even = chitu_array_even(a);
    double output = 0;

    for (uint64_t i = 0; i < a->length; i++)
        output += pow(a->val[i] - a_even, 2);
    
    return output / a->length;
}

inline double chitu_array_standard_deviation(chitu_array *a)
{
    return chitu_sqrt(chitu_array_variance(a));
}

void chitu_array_max(chitu_array *a, double *result)
{
    double n = DBL_MIN;

    if (a->length == 0)
    {
        result = NULL;
        return;
    }

    for (uint64_t i = 0; i < a->length; i++)
        if (a->val[i] > n)
            n = a->val[i];
    *result = n;
}

void chitu_array_min(chitu_array *a, double *result)
{
    double n = DBL_MAX;

    if (a->length == 0)
    {
        result = NULL;
        return;
    }

    for (uint64_t i = 0; i < a->length; i++)
        if (a->val[i] < n)
            n = a->val[i];
    *result = n;
}

int sort_cmp(const void *a, const void *b)
{
    double front, tear;
    front = *(double *)a;
    tear = *(double *)b;
    return front > tear ? 1 : -1;
}

void chitu_array_sort(chitu_array *a)
{
    qsort(a->val, a->length, sizeof(double), sort_cmp);
}

void chitu_array_reverse(chitu_array *a)
{
    double tmp;
    for (uint64_t i = 0; i < a->length / 2; i++)
    {
        tmp = a->val[i];
        a->val[i] = a->val[a->length - 1 - i];
        a->val[a->length - 1 - i] = tmp;
    }
}

void chitu_array_random(chitu_array *a)
{
    for (uint64_t i = 0; i < a->length; i ++)
        a->val[i] = chitu_random();
}

void chitu_array_randint(chitu_array *a, int64_t start, int64_t end)
{
    for (uint64_t i = 0; i < a->length; i ++)
        a->val[i] = chitu_randint(start, end);
}

void chitu_array_randfloat(chitu_array *a, double start, double end)
{
    for (uint64_t i = 0; i < a->length; i++)
        a->val[i] = chitu_randfloat(start, end);
}

inline double chitu_array_choice(chitu_array *a)
{
    return a->val[chitu_randint(0, a->length)];
}

//四则运算
    //对单个数字运算
void chitu_array_plus(chitu_array *a, double n)
{
    for (uint64_t i = 0; i < a->length; i++)
        a->val[i] += n;
}

void chitu_array_minus(chitu_array *a, double n)
{
    for (uint64_t i = 0; i < a->length; i++)
        a->val[i] -= n;
}

void chitu_array_mutiplys(chitu_array *a, double n)
{
    for (uint64_t i = 0; i < a->length; i++)
        a->val[i] *= n;
}

void chitu_array_divide(chitu_array *a, double n)
{
    for (uint64_t i = 0; i < a->length; i++)
        a->val[i] /= n;
}

void chitu_array_mod(chitu_array *a, double n)
{
    for (uint64_t i = 0; i < a->length; i++)
        a->val[i] = fmod(a->val[i], n);
}
    //对数组运算
void chitu_array_plusa(chitu_array *a, chitu_array *b)
{
    uint64_t stopindex = a->length < b->length ? a->length : b->length;

    for (uint64_t i = 0; i < stopindex; i++)
        a->val[i] += b->val[i];
}

void chitu_array_minusa(chitu_array *a, chitu_array *b)
{
    uint64_t stopindex = a->length < b->length ? a->length : b->length;

    for (uint64_t i = 0; i < stopindex; i++)
        a->val[i] -= b->val[i];
}

void chitu_array_mutiplysa(chitu_array *a, chitu_array *b)
{
    uint64_t stopindex = a->length < b->length ? a->length : b->length;

    for (uint64_t i = 0; i < stopindex; i++)
        a->val[i] *= b->val[i];
}

void chitu_array_dividea(chitu_array *a, chitu_array *b)
{
    uint64_t stopindex = a->length < b->length ? a->length : b->length;

    for (uint64_t i = 0; i < stopindex; i++)
        a->val[i] /= b->val[i];
}

void chitu_array_moda(chitu_array *a, chitu_array *b)
{
    uint64_t stopindex = a->length < b->length ? a->length : b->length;

    for (uint64_t i = 0; i < stopindex; i++)
        a->val[i] = fmod(a->val[i], b->val[i]);
}


//指数运算
void chitu_array_squre(chitu_array *a)
{
    for (uint64_t i = 0; i < a->length; i++)
        a->val[i] *= a->val[i];
}

void chitu_array_sqrt(chitu_array *a)
{
    for (uint64_t i = 0; i < a->length; i++)
        a->val[i] = chitu_sqrt(a->val[i]);
}

void chitu_array_cube(chitu_array *a)
{
    for (uint64_t i = 0; i < a->length; i++)
        a->val[i] = chitu_cube(a->val[i]);
}

void chitu_array_cbrt(chitu_array *a)
{
    for (uint64_t i = 0; i < a->length; i++)
        a->val[i] = chitu_cbrt(a->val[i]);
}

void chitu_array_pow(chitu_array *a, double n)
{
    for (uint64_t i = 0; i < a->length; i++)
        a->val[i] = chitu_pow(a->val[i], n);
}
